package com.tcoding.client.gui.sidemenu;

import com.jfoenix.assets.JFoenixResources;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXTabPane;
import com.tcoding.client.MainDemo;
import com.tcoding.client.bean.MenuVoCell;
import com.tcoding.client.utils.SvgGraphicUtil;
import com.tcoding.client.websocket.CustomEventListener;
import com.tcoding.client.websocket.CustomEventManager;
import com.tcoding.client.websocket.GlobalContextMenuActionEvent;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.Flow;
import io.datafx.controller.flow.FlowException;
import io.datafx.controller.flow.FlowHandler;
import io.datafx.controller.flow.container.AnimatedFlowContainer;
import io.datafx.controller.flow.container.ContainerAnimations;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.util.Duration;
import com.tcoding.client.gui.contextmenu.GlobalMenu;
import com.tcoding.client.gui.feature.FeatureResourceConsumer;
import com.tcoding.core.vo.MenuVO;
import com.tcoding.client.store.ApplicationStore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.kordamp.ikonli.javafx.FontIcon;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@Slf4j
@ViewController(value = "/fxml/SideMenu.fxml", title = "Material Design Example")
public class SideMenuController {

    @FXMLViewFlowContext
    private ViewFlowContext context;
    @FXML
    private JFXListView<Object> customerSideList;

//    private final LinkedHashMap<String, Tab> tabsMap = new LinkedHashMap<>();
//    private final LinkedHashMap<String, String> globalLinkMap = new LinkedHashMap<>();

    @Inject
    private FeatureResourceConsumer featureResourceConsumer;

    private JFXTabPane mainTabPane;

    private ObservableValue<Boolean> menuExpand;


    /**
     * init fxml when loaded.
     */
    @PostConstruct
    public void init() {
        Objects.requireNonNull(context, "context");
        JFXTabPane tabPane = (JFXTabPane) context.getRegisteredObject("ContentPane");
        context.register("mainLeftMenu",customerSideList);
        this.mainTabPane = tabPane;
        //清空
        tabPane.getTabs().clear();
        customerSideList.getItems().clear();
        initMenu();
        registListener();
        customerSideList.propagateMouseEventsToParent();
        ObservableList<Object> items = customerSideList.getItems();
        Iterator<Object> iterator = items.stream().iterator();
        customerSideList.getSelectionModel().selectedItemProperty().addListener((o, oldVal, newVal) -> new Thread(() -> {
            Platform.runLater(() -> {
                if (newVal != null) {
                    try {
                        if (newVal instanceof Label) {
                            Label menuVO = (Label) newVal;
                            addTab(menuVO.getText(), null, MenuConstant.globalLinkMap.get(menuVO.getId()), menuVO.getUserData(), tabPane);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            });
        }).start());

        while (iterator.hasNext()) {
            Object next1 = iterator.next();
            if (next1 instanceof Label) {
                System.out.println("adsdad...." + ((Label) next1).getText());
            } else {
                JFXListView<Label> next = (JFXListView<Label>) next1;
                next.getSelectionModel().selectedItemProperty().addListener((o, oldVal, newVal) -> new Thread(() -> {
                    Platform.runLater(() -> {
                        if (newVal != null) {
                            try {
                                addTab(newVal.getText(), null, MenuConstant.globalLinkMap.get(newVal.getId()), newVal.getUserData(), tabPane);
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }).start());
            }


        }
        //设置首页
        String dashboardText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? "首页" : "home";
        try {
            addTab(dashboardText, null,"com.tcoding.client.controller.uicomponents.HomeController", "home", tabPane);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {

            if (newValue != null) {
                String text = newValue.getText();
                int j = 0;
                for (Object jfxListView : items) {
                    if (jfxListView instanceof Label) {
                        if(StringUtils.equals(text,((Label) jfxListView).getText())){
                            customerSideList.getSelectionModel().select(jfxListView);
                            break;
                        }
                        continue;
                    }
                    JFXListView<Label> jfxListView2 = (JFXListView<Label>) jfxListView;
                    ObservableList<Label> listViewItems = jfxListView2.getItems();
                    for (int i = 0; i < listViewItems.size(); i++) {
                        Label label = listViewItems.get(i);
                        if (label.getText().equals(text)) {
                            jfxListView2.getSelectionModel().select(i);
//                        customerSideList.getSelectionModel().select(j);
                            break;
                        }
                    }
                    j++;
                }
            }

        });
    }

    private void initMenu() {
        MenuConstant.tabsMap.clear();
        MenuConstant.globalLinkMap.clear();
        ListProperty<MenuVoCell> listProperty = ApplicationStore.getMenuVoCells();
        listProperty.sort(Comparator.comparing(o -> o.getMenuVO().getOrderNum()));
        for (MenuVoCell menuVoCell : listProperty) {
            String menuText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? menuVoCell.getMenuVO().getTitle() : menuVoCell.getMenuVO().getCode();

            if (menuVoCell.getChildrenMenus().isEmpty()) {
                FontIcon fontIcon = new FontIcon(StringUtils.isBlank(menuVoCell.getMenuVO().getIcon()) ? "fas-smile" : menuVoCell.getMenuVO().getIcon());
                fontIcon.setIconSize(12);
                Label nodeLabel = new Label(menuText, fontIcon);
                nodeLabel.setId(menuVoCell.getMenuVO().getCode());
                nodeLabel.setUserData(menuVoCell.getMenuVO());
                nodeLabel.getStyleClass().add("first-label");
                MenuConstant.globalLinkMap.put(menuVoCell.getMenuVO().getCode(), menuVoCell.getMenuVO().getHref());
                customerSideList.getItems().add(nodeLabel);
            } else {
                JFXListView<Label> listView = new JFXListView<>();
                listView.getStyleClass().add("sublist");
                Label label = null;
                try {
                    FontIcon fontIcon = new FontIcon(StringUtils.isBlank(menuVoCell.getMenuVO().getIcon()) ? "fas-smile" : menuVoCell.getMenuVO().getIcon());
                    fontIcon.setIconSize(12);
                    label = new Label(menuText, fontIcon);
                    label.getStyleClass().add("sub-label");
                    label.setUserData(menuVoCell);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Objects.requireNonNull(label).setTextAlignment(TextAlignment.LEFT);
                listView.setGroupnode(label);
                ObservableList<MenuVO> childrenMenus = menuVoCell.getChildrenMenus();
                childrenMenus.sort(Comparator.comparing(MenuVO::getOrderNum));
                for (MenuVO menuVO : childrenMenus) {
                    String childMenuText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? menuVO.getTitle() : menuVO.getCode();
                    Label nodeLabel = new Label(childMenuText);
                    nodeLabel.setId(menuVO.getCode());
                    nodeLabel.setUserData(menuVO);
                    MenuConstant.globalLinkMap.put(menuVO.getCode(), menuVO.getHref());
                    listView.getItems().add(nodeLabel);
                }
                customerSideList.getItems().add(listView);
            }
        }
    }

    /**
     * @Description:添加tab页
     * @param: [flow]
     * @return: void
     * @auther: liwen
     * @date: 2020/6/28 9:57 上午
     */
    public static <T> void addTab(String title, Node icon, String uri, Object userData, JFXTabPane tabPane) throws ClassNotFoundException {
        ApplicationStore.showProgress();
        if(StringUtils.startsWithAny(uri,"http","https")){
            openInBrowser(uri,title,userData,tabPane);
            return;
        }

        Flow flow = new Flow(Class.forName(uri));
        FlowHandler flowHandler = flow.createHandler();
        if (userData instanceof String) {
            openInTab(title, icon, flow, userData, tabPane, flowHandler);
        } else {
            MenuVO menuVO = (MenuVO) userData;
            if (StringUtils.equals(menuVO.getOpenType(), "1")) {
                openInNewWindow(flowHandler,title,icon,userData);
            } else {
                openInTab(title, icon, flow, userData, tabPane, flowHandler);
            }
        }
    }

    public static void openInBrowser(String uri,String title,Object userData,JFXTabPane tabPane){
        String tabId = "";
        if(userData instanceof String){
            tabId = userData.toString();
        }else {
            MenuVO menuVO = (MenuVO) userData;
            tabId = menuVO.getCode();
        }

        Tab tab = MenuConstant.tabsMap.get(title);
        if (tab == null) {
            tab = new Tab(title);
            tab.setId(tabId);
            tab.setUserData(userData);
            WebView webView = new WebView();
            final WebEngine webEngine = webView.getEngine();
            webEngine.load(uri);
            StackPane node = new StackPane();
            node.getChildren().add(webView);
            node.getStyleClass().addAll("tab-content");
            node.setPadding(new Insets(0, 0, 0, 0));
            tab.setContent(node);
            tabPane.getTabs().add(tab);
            MenuConstant.tabsMap.put(title, tab);
            tab.setOnClosed(event -> {
                MenuConstant.tabsMap.remove(title);
            });
            tab.setContextMenu(GlobalMenu.getInstance(tab.getUserData()));
        }

        if (StringUtils.equals(title, "home") || StringUtils.equals(title, "首页")) {
            tab.setClosable(false);
        }
        tabPane.getSelectionModel().select(tab);

        ApplicationStore.hideProgress();
    }

    public void openBrowserInNewWindow(String uri,String title){
        WebView webView = new WebView();
        final WebEngine webEngine = webView.getEngine();
        webEngine.load(uri);
        Scene scene = new Scene(webView);
        Stage newStage = new Stage();
        newStage.setWidth(800);
        newStage.setHeight(600);
        newStage.setTitle(title);
        newStage.setScene(scene);
        newStage.show();
        ApplicationStore.hideProgress();
    }

    public static void openInNewWindow(FlowHandler flowHandler,String title, Node icon,Object userData) {
        StackPane node = null;
        try {
            node = flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.SWIPE_LEFT));
            node.setPadding(new Insets(10));
            Scene scene = new Scene(node);
            final ObservableList<String> stylesheets = scene.getStylesheets();
            stylesheets.addAll(JFoenixResources.load("css/jfoenix-fonts.css").toExternalForm(),
                    JFoenixResources.load("css/jfoenix-design.css").toExternalForm(),
                    MainDemo.class.getResource("/css/chenfei/color.css").toExternalForm(),
                    MainDemo.class.getResource("/css/chenfei/core.css").toExternalForm(),
                    MainDemo.class.getResource("/css/theme/jfoenix-main-dark.css").toExternalForm()
            );
            Stage newStage = new Stage();
            newStage.setWidth(800);
            newStage.setHeight(600);
            newStage.setTitle(title);
            newStage.setScene(scene);
            newStage.show();
            newStage.setOnCloseRequest(action -> {
                // TODO: 2022/9/6

            });
        } catch (FlowException e) {
            e.printStackTrace();
        }
        ApplicationStore.hideProgress();
    }

    private static void openInTab(String title, Node icon, Flow flow, Object userData, JFXTabPane tabPane, FlowHandler flowHandler) {

        String tabId = "";
        if(userData instanceof String){
            tabId = userData.toString();
        }else {
            MenuVO menuVO = (MenuVO) userData;
            tabId = menuVO.getCode();
        }

        Tab tab = MenuConstant.tabsMap.get(title);
        if (tab == null) {
            tab = new Tab(title);
            tab.setId(tabId);
            tab.setGraphic(icon);
            tab.setUserData(userData);
            try {
                StackPane node = flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.FADE));
                node.getStyleClass().addAll("tab-content");
                node.setPadding(new Insets(10, 10, 15, 10));
                tab.setContent(node);

            } catch (FlowException e) {
                e.printStackTrace();
            }
            tabPane.getTabs().add(tab);
            MenuConstant.tabsMap.put(title, tab);
            tab.setOnClosed(event -> {
                MenuConstant.tabsMap.remove(title);
                try {
                    flowHandler.getCurrentViewContext().destroy();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            });

            tab.setContextMenu(GlobalMenu.getInstance(tab.getUserData()));

        }

        if (StringUtils.equals(title, "home") || StringUtils.equals(title, "首页")) {
            tab.setClosable(false);
        }
        tabPane.getSelectionModel().select(tab);
        ApplicationStore.hideProgress();
    }

    private void registListener(){
        CustomEventManager.addListener(new CustomEventListener<GlobalContextMenuActionEvent>() {

            /**
             * 处理器
             *
             * @param globalContextMenuActionEvent
             */
            @Override
            public void handler(GlobalContextMenuActionEvent globalContextMenuActionEvent) throws ClassNotFoundException {
                Object value = null;
                switch (globalContextMenuActionEvent.getAction()){

                    case OPEN:
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            return;
                        }
                        MenuVO menuVO = (MenuVO) value;
                        String s = MenuConstant.globalLinkMap.get(menuVO.getCode());
                        if(StringUtils.startsWithAny(s,"http","https")){
                            mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), menuVO.getCode()));
                            MenuConstant.tabsMap.remove(menuVO.getTitle());
                            openBrowserInNewWindow(s, menuVO.getTitle());
                            return;
                        }
                        Flow flow = new Flow(Class.forName(s));
                        FlowHandler flowHandler = flow.createHandler();
                        mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), menuVO.getCode()));
                        MenuConstant.tabsMap.remove(menuVO.getTitle());
                        openInNewWindow(flowHandler, menuVO.getTitle(), null,menuVO);
                        break;
                    case CLOSE_ALL:
                        Iterator<Map.Entry<String, Tab>> iterator = MenuConstant.tabsMap.entrySet().iterator();
                        while (iterator.hasNext()){
                            Map.Entry<String, Tab> next = iterator.next();
                            if(StringUtils.equalsAny(next.getKey(),"首页","home")){
                                continue;
                            }
                            iterator.remove();
                        }
                        mainTabPane.getTabs().removeIf(tab -> !StringUtils.equalsAny(tab.getId(),"首页","home"));
                        break;
                    case CLOSE_CURRENT:
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            return;
                        }
                        MenuVO currentMenu = (MenuVO) value;
                        mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), currentMenu.getCode()));
                        MenuConstant.tabsMap.remove(currentMenu.getTitle());
                        break;
                    case CLOSE_RIGHT:
                        String currentTile = "";
                        Iterator<Map.Entry<String, Tab>> iterator1 = MenuConstant.tabsMap.entrySet().iterator();
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            Object[] objects = MenuConstant.tabsMap.entrySet().toArray();
                            currentTile = ((Map.Entry) objects[0]).getKey().toString();
                        }else {
                            MenuVO currentMenu2 = (MenuVO) value;
                            currentTile = currentMenu2.getTitle();
                        }
                        int index=1,fromIndex = 1;
                        while (iterator1.hasNext()){
                            if(StringUtils.equals(iterator1.next().getKey(),currentTile)){
                                fromIndex = index;
                            }else {
                                index++;
                            }
                            if(index>fromIndex){
                                iterator1.remove();
                            }
                        }
                        mainTabPane.getTabs().remove(fromIndex,mainTabPane.getTabs().size());
                        break;
                    default:
                }

            }
        });
    }
}
